package org.takeback.chat.service;

import com.google.common.collect.ImmutableMap;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.takeback.chat.entity.Message;
import org.takeback.chat.entity.PcConfig;
import org.takeback.chat.entity.PcGameLog;
import org.takeback.chat.entity.PcRateConfig;
import org.takeback.chat.entity.PubUser;
import org.takeback.chat.lottery.Lottery;
import org.takeback.chat.lottery.listeners.GameException;
import org.takeback.chat.store.pcegg.PcEggStore;
import org.takeback.chat.store.room.LotteryFactory;
import org.takeback.chat.store.room.LotteryFactory.DefaultLotteryBuilder;
import org.takeback.chat.store.room.Room;
import org.takeback.chat.store.room.RoomStore;
import org.takeback.chat.store.user.User;
import org.takeback.chat.store.user.UserStore;
import org.takeback.chat.utils.MessageUtils;
import org.takeback.dao.BaseDAO;
import org.takeback.service.BaseService;
import org.takeback.util.exception.CodedBaseRuntimeException;

@Service
public class PcEggService extends BaseService {
	@Autowired
	RoomStore roomStore;
	@Autowired
	UserStore userStore;
	public static final Integer[] red = { Integer.valueOf(3), Integer.valueOf(6), Integer.valueOf(9),
			Integer.valueOf(12), Integer.valueOf(15), Integer.valueOf(18), Integer.valueOf(21), Integer.valueOf(24) };
	public static final Integer[] green = { Integer.valueOf(1), Integer.valueOf(4), Integer.valueOf(7),
			Integer.valueOf(10), Integer.valueOf(16), Integer.valueOf(19), Integer.valueOf(22), Integer.valueOf(25) };
	public static final Integer[] blue = { Integer.valueOf(2), Integer.valueOf(5), Integer.valueOf(8),
			Integer.valueOf(11), Integer.valueOf(17), Integer.valueOf(20), Integer.valueOf(23), Integer.valueOf(26) };

	@Transactional(readOnly = true)
	public Map<String, PcRateConfig> getPcRateConfig() {
		Map<String, PcRateConfig> config = new HashMap();
		List<PcRateConfig> list = this.dao.findByHql("from PcRateConfig order by id , catalog ");
		for (PcRateConfig c : list) {
			config.put(c.getParam(), c);
		}
		return config;
	}

	@Transactional(readOnly = true)
	public Map<String, List<PcRateConfig>> getPcRateConfigs() {
		Map<String, List<PcRateConfig>> rates = new HashMap();
		List<PcRateConfig> list = this.dao.findByHql("from PcRateConfig order by id, catalog ");
		for (PcRateConfig config : list) {
			List<PcRateConfig> prc = (List) rates.get(config.getCatalog());
			if (prc == null) {
				prc = new ArrayList();
				rates.put(config.getCatalog(), prc);
			}
			prc.add(config);
		}
		return rates;
	}

	private List<Double> getValues(String text) {
		List<Double> res = new ArrayList();
		String pattern = "【[0-9]+】";
		Pattern p = Pattern.compile(pattern);
		Matcher m = p.matcher(text);
		while (m.find()) {
			res.add(Double.valueOf(m.group().replaceAll("[【】]", "")));
		}
		return res;
	}

	@Transactional
	public Map<String, List<Double>> getLimitConfig() {
		Map<String, List<Double>> config = new HashMap();
		List<PcConfig> list = this.dao.findByHql("from PcConfig where param like 'l_%'  order by id");
		for (PcConfig c : list) {
			config.put(c.getParam(), getValues(c.getVal()));
		}
		return config;
	}

	@Transactional
	public void bet(Integer num, String key, Double money, Integer uid, String roomId) {
		if (PcEggStore.getStore().isClosed(num.intValue())) {
			throw new CodedBaseRuntimeException(num + "期已停止下注!");
		}
		String moneyHql = "update PubUser set money = COALESCE(money,0) - :money where id=:uid and money>:money";
		int effected = this.dao.executeUpdate(moneyHql, ImmutableMap.of("money", money, "uid", uid));
		if (effected == 0) {
			throw new CodedBaseRuntimeException("账户金额不足,请及时充值!");
		}
		Map<String, PcRateConfig> rates = getPcRateConfig();

		PcRateConfig rateConf = (PcRateConfig) rates.get(key);
		if (rateConf == null) {
			throw new CodedBaseRuntimeException("非法的下注值：" + key);
		}
		Map<String, List<Double>> limitConf = getLimitConfig();
		Double min = (Double) ((List) limitConf.get("l_6")).get(0);
		Double max = (Double) ((List) limitConf.get("l_1")).get(0);
		if ((money.doubleValue() < min.doubleValue()) || (money.doubleValue() > max.doubleValue())) {
			throw new CodedBaseRuntimeException("下注金额范围在:" + min + "-" + max + "之间");
		}
		PcGameLog pgl = new PcGameLog();
		pgl.setBet(key);
		pgl.setNum(num);
		pgl.setFreeze(money.doubleValue());
		pgl.setBetTime(new Date());
		pgl.setBetType(rateConf.getCatalog());
		pgl.setUid(uid);
		pgl.setStatus("0");
        pgl.setAddBack(0.0);
		PubUser user = (PubUser) this.dao.get(PubUser.class, uid);
		pgl.setUserId(user.getUserId());
		this.dao.save(PcGameLog.class, pgl);

		String text = ((PcRateConfig) rates.get(key)).getAlias();
		if ("num".equals(rateConf.getCatalog())) {
			text = "数字" + text;
		}
		Lottery lottery = LotteryFactory.getDefaultBuilder(new BigDecimal(money.doubleValue()), Integer.valueOf(1))
				.setExpiredSeconds(Integer.valueOf(1)).setType("2").setTitle(text + " " + money + "金币")
				.setSender(uid.intValue()).setDescription(num + "期").build();
		try {
			lottery.open(0);
		} catch (GameException e) {
			e.printStackTrace();
		}
		Message redMessage = new Message(Message.RED, uid, lottery);
		User u = (User) this.userStore.get(uid);
		redMessage.setHeadImg(u.getHeadImg());
		redMessage.setNickName(u.getNickName());
		redMessage.setMsgTime(new Date());
		Room room = (Room) this.roomStore.get(roomId);
		MessageUtils.broadcast(room, redMessage);
	}

	@Transactional
	public List<PcGameLog> getGameLog(Integer num) {
		return this.dao.findByHql("from PcGameLog where num =:num and status =0", ImmutableMap.of("num", num));
	}

	@Transactional
	public void open(Integer num, String exp, String val) {
		Map<String, PcRateConfig> rates = getPcRateConfig();

		Integer intVal = Integer.valueOf(val);
		List<PcGameLog> gameRecs = this.dao.findByHql("from PcGameLog where num =:num and status =0",
				ImmutableMap.of("num", num));
		List<String> otherLucky = getSpecialLucky(val, exp);
		for (PcGameLog l : gameRecs) {
			Double rate = Double.valueOf(0.0D);
			String betType = l.getBetType();
			l.setLuckyNumber(exp);
			l.setOpenTime(new Date());
			if ("num".equals(betType)) {
				if (intVal.toString().equals(l.getBet())) {
					rate = Double.valueOf(((PcRateConfig) rates.get(intVal.toString())).getVal());
				}
			} else {
				for (String key : otherLucky) {
					if (key.equals(l.getBet())) {
						rate = Double.valueOf(((PcRateConfig) rates.get(key)).getVal());
					}
				}
			}
			if (rate.doubleValue() > 0.0D) {
				Double betMoney = Double.valueOf(l.getFreeze());
				Double bonus = Double.valueOf(betMoney.doubleValue() * rate.doubleValue());
				l.setAddBack(bonus.doubleValue());
				l.setBackMoney(0.0D);
				l.setBonus(bonus.doubleValue());
				l.setUserInout(bonus.doubleValue() - betMoney.doubleValue());
				l.setStatus("1");
				this.dao.executeUpdate("update PubUser set money = money +:bonus where id =:uid",
						ImmutableMap.of("bonus", bonus, "uid", l.getUid()));
			} else {
				Integer uid = l.getUid();

				l.setBonus(0.0D);
				l.setAddBack(0.0D);
				l.setUserInout(-l.getFreeze());
				l.setStatus("2");
			}
			this.dao.save(PcGameLog.class, l);
		}
	}

	public List<String> getSpecialLucky(String val, String exp) {
		List res = new ArrayList();
		Integer intVal = Integer.valueOf(val);
        if (intVal % 2 == 0) {
            res.add("sh");
            if (intVal >= 14) {
                res.add("ds");
            }
            else if (intVal < 13) {
                res.add("xs");
            }
        }
        else {
            res.add("dn");
            if (intVal > 14) {
                res.add("dd");
            }
            else if (intVal <= 13) {
                res.add("xd");
            }
        }
        if (intVal >= 14) {
            res.add("da");
        }
        else if (intVal <= 13) {
            res.add("xo");
        }
        if (intVal >= 22) {
            res.add("jd");
        }
        if (intVal <= 5) {
            res.add("jx");
        }
        for (final int i : PcEggService.red) {
            if (i == intVal) {
                res.add("rd");
            }
        }
        for (final int i : PcEggService.green) {
            if (i == intVal) {
                res.add("grn");
            }
        }
        for (final int i : PcEggService.blue) {
            if (i == intVal) {
                res.add("bl");
            }
        }
        if ("8+8+8".equals(exp)) {
            res.add("bz");
        }
		
		return res;
	}
}
